<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 递归次数太多会造成堆栈溢出
        // 函数在没有完全执行结束时，内部的所有变量都不会被销毁
        // 递归会建立一个函数的副本，在堆中建立相同的函数引用，递归时调用这个新的函数引用    
        //  --------------------------------    

        // 不能在同一个函数内定义两个相同的局部变量，在副本中建立局部变量
        //     var i=0;
        // function fn1(){
        //     //   假设是fn执行时的局部变量var a=3;
        //             i++;
        //         if(i<3) fn1();
        //         console.log(i);
        //     }
        //     fn1();
        // 输出结果为3个3 fn1在执行时，i++后，变为1，小于3后，再次执行fn1，此时不会输出结果
        // 直到a的值大于3时，跳出循环，此时a=0的循环完成，因为a相当于局部变量，不会改变，所以当
        // a=1和a等于2时，再循环两次，结果输出为3个3

        //    -----------------------------------------------   

        var i = 0;
        function fn1() {
            i++;
            console.log(i);
            if (i < 3) fn1();

        }
        fn1();
        // 输出结果为1 2 3   循环3次，当i>3时跳出函数，循环结束
        // -----------------------------------------------------------------------


        // var obj = { value: 1, next: { value: 2, next: { value: 3, next: { value: 4, next: { value: 5, next: null } } } } };

        // function fn1(obj) {
        //     console.log(obj.value);
        //     if (obj.next) fn1(obj.next);
        // }

        // fn1(obj);

        // 执行过程：当执行fn1时，将obj带入函数中，将value值输出为1，判断如果 obj.next 存在，则会执行fn1
        // 此时的fn1是value: 2, next之后的代码，将会输出2，再次执行函数，直到函数执行完毕

        // ------------------------------------------------------------------------------------------------------


        // 对象的广度遍历使用for in
        // 对象的深度遍历使用递归



        //     function fn1(obj){
        //     for(var prop in obj){
        //         console.log(prop,obj[prop]);
        //         if(typeof obj[prop]==="object" && obj[prop]!==null) fn1(obj[prop])
        //     }
        // }

        // fn1(obj);
        // 面对对象里包含对象，要查找某个对象时，这个程序结合了广度遍历和深度遍历，在执行fn1时，先是广度遍历
        // 一个对象，再利用深度遍历（递归），循环执行，就能找到所要找的元素

        // --------------------------------------------------------------------------------------------------------        



        // 对象深复制：
        //   function fn1(source,target){
        //       if(target===undefined) target={};
        //         for(var prop in source){
        //             if(typeof source[prop]==="object" && source[prop]!==null){
        //               target[prop]={};
        //               fn1(source[prop],target[prop])
        //             }
        //             else {
        //               target[prop]=source[prop];
        //             }
        //         }
        //         return target;
        //     }
        //     var o=fn1(obj);
        //     console.log(o);


        // 执行过程：执行fn1 时，将obj带入到source里，判断target没有时，则target为空对象，那么这个target对象是重新创建的局部变量
        // 然后遍历source，如果source对象是一个对象且不为空，于是给target下的prop对象设置为空对象，就会判定target下的prop对象和source下的prop对象不是同一个对象
        // 再次执行fn1 时，就意味着再次遍历这两个对象，如果不是对象时，就直接让目标对象等于原对象，由于是两个对象相等不会改变属性

        // ------------------------------------------------------------------------------------------------------------------------------------------

        // 二叉树遍历：

        // var obj = {
        //     value: 0,
        //     left: {
        //         value: 1,
        //         left: {
        //             value: 3,
        //         },
        //         right: {
        //             value: 4,
        //         }
        //     },
        //     right: {
        //         value: 2,
        //         left: {
        //             value: 5,
        //         },
        //         right: {
        //             value: 6
        //         }
        //     }
        // }

        // 方法1 - 前序遍历
        // function fn1(o) {
        //     console.log(o.value);
        //     if (o.left) fn1(o.left);
        //     if (o.right) fn1(o.right);
        // }
        // fn1(obj);



        // 方法1 - 中序遍历
        // function fn1(o) {
        //     if (o.left) fn1(o.left);
        //     console.log(o.value);
        //     if (o.right) fn1(o.right);
        // }
        // fn1(obj);



        // 方法1 - 后序遍历
        // function fn1(o) {
        //     if (o.left) fn1(o.left);
        //     if (o.right) fn1(o.right);
        //     console.log(o.value);
        // }
        // fn1(obj);

        // ------------------------------------------------------------------------------------

        // return在递归中的变化


        // 求每次计算的余数：
        // function fn1(n, str) {
        //     if (str === undefined) str = "";
        //     str = (n % 2) + str;
        //     n = parseInt(n / 2); //7
        //     if (n) return fn1(n, str);
        //     return str;
        // }
        //     var a = fn1(15);
        //     console.log(a);
        // 执行过程：当str为空时，就让str等于空字符串， str = (n % 2) + str;执行这一步时，需要把余数取出来，不然循环结束后顺序会翻转为000001
        // 进入循环后，return fn1(n, str);这个return很关键，是将最后循环的值返回出去，再由外边的return返回给fn1

        // ---------------------------------------------------------------------------------------------------------------------------------------



        function fn(elem) {
            if (elem.innerHTML === "我的产品") {
                return elem;
            }
            for (var i = 0; i < elem.children.length; i++) {
                var e = fn(elem.children[i]);
                if (e) return e;
            }
        }
        var elem = fn(document.body);
        console.log(elem);

        在HTML中查找某个div里内容

        // ------------------------------------------


        // 深查找：
        function fn3(o, value) {
            for (var prop in o) {
                if (o[prop] === value) return prop;
                if (typeof o[prop] === "object" && o[prop] !== null) {
                    var s = fn3(o[prop], value)
                    if (s) return s;
                }
            }
        }





    </script>
</body>

</html>